#![cfg(test)]

use super::*;
use std::rc::Rc;

mod test_l_n {
    use super::*;
    use paste::paste;
    use std::array;

    // 测试单个L值下的所有N情况
    macro_rules! test_for_l {
        ($L:expr) => {
            paste! {
                #[test]
                fn [<test_slides_l $L>]() {
                    test_case::<$L, 0>();
                    test_case::<$L, 1>();
                    test_case::<$L, 2>();
                    test_case::<$L, 3>();
                    test_case::<$L, 4>();
                    test_case::<$L, 5>();
                    test_case::<$L, 6>();
                    test_case::<$L, 7>();
                    test_case::<$L, 8>();
                    test_case::<$L, 9>();
                    test_case::<$L, 10>();
                    test_case::<$L, 11>();
                    test_case::<$L, 12>();
                    test_case::<$L, 13>();
                    test_case::<$L, 14>();
                    test_case::<$L, 15>();
                }
            }
        };
    }

    // 特定L和N的测试用例
    fn test_case<const L: usize, const N: usize>() {
        // 初始化队列
        let init_arr = array::from_fn(|i| i);
        let mut queue = SlidingQueue::<L, usize>::new(init_arr);

        // 准备新元素
        let new_items: [_; N] = array::from_fn(|i| L + i);
        let popped = queue.slides(new_items);

        // 验证弹出元素
        let expected_popped: Vec<usize> = if N <= L {
            (0..N).collect()
        } else {
            (0..L).chain(L..L + (N - L)).collect()
        };
        assert_eq!(
            popped.as_slice(),
            expected_popped.as_slice(),
            "L={}, N={} popped mismatch",
            L,
            N
        );

        // 验证队列内容
        let expected_queue: Vec<usize> = if N <= L {
            (N..L).chain(L..L + N).collect()
        } else {
            (N..N + L).collect()
        };
        assert_eq!(
            queue.as_ref(),
            expected_queue.as_slice(),
            "L={}, N={} queue mismatch",
            L,
            N
        );

        // === 新增的单独slide测试 ===
        let new_val = L + N; // 新值
        let popped_single = queue.slide(new_val);

        // 验证slide弹出值
        let expected_slide_pop = expected_queue[0];
        assert_eq!(
            popped_single, expected_slide_pop,
            "L={}, N={} slide pop mismatch",
            L, N
        );

        // 验证slide后的队列内容
        let mut expected_after_slide: Vec<usize> = if N <= L {
            // 原队列去掉第一个元素 + 新值
            expected_queue[1..]
                .iter()
                .copied()
                .chain(Some(new_val))
                .collect()
        } else {
            // 当N>L时，队列已经是[N..N+L]，滑动后变成[N+1..N+L+1]
            (N + 1..N + L + 1).collect()
        };

        // 确保长度正确
        expected_after_slide.truncate(L);

        assert_eq!(
            queue.as_ref(),
            expected_after_slide.as_slice(),
            "L={}, N={} after slide queue mismatch",
            L,
            N
        );

        // 验证take方法
        let taken = queue.take();
        assert_eq!(
            taken.as_slice(),
            expected_after_slide.as_slice(),
            "L={}, N={} take mismatch",
            L,
            N
        );
    }

    // 生成L=1到5的测试
    test_for_l!(1);
    test_for_l!(2);
    test_for_l!(3);
    test_for_l!(4);
    test_for_l!(5);

    // 特殊边界测试
    #[test]
    fn test_zero_length() {
        let arr: [usize; 0] = [];
        let mut queue = SlidingQueue::<3, usize>::new([1, 2, 3]);

        // N=0时不应修改队列
        let popped = queue.slides(arr);
        assert!(popped.is_empty());
        assert_eq!(queue.as_ref(), &[1, 2, 3]);

        // 测试slide操作
        let popped_single = queue.slide(4);
        assert_eq!(popped_single, 1);
        assert_eq!(queue.as_ref(), &[2, 3, 4]);
    }

    #[test]
    #[ignore]
    #[should_panic(expected = "L must not zero")]
    fn test_l_zero_panic() {
        let _: SlidingQueue<0, usize> = SlidingQueue::new([]);
    }
}

#[test]
fn test_string() {
    let datas = ["0".to_string(), "1".to_string(), "2".to_string()];
    let mut queue = SlidingQueue::new(datas.clone());

    assert_eq!(&*queue, datas);

    let new_data3 = "3".to_string();
    assert_eq!(queue.slide(new_data3.clone()), "0");

    let new_data4 = "4".to_string();
    assert_eq!(queue.slide(new_data4.clone()), "1");

    let new_data5 = "5".to_string();
    assert_eq!(queue.slide(new_data5.clone()), "2");

    let datas = [new_data3, new_data4, new_data5];

    assert_eq!(&*queue, datas.clone());

    assert_eq!(queue.slides(datas.clone()), datas);
}

// 创建带计数器的 Rc 包装器
#[derive(Clone)]
struct TestRc(Rc<()>);

impl TestRc {
    fn new() -> Self {
        TestRc(Rc::new(()))
    }

    fn count(&self) -> usize {
        Rc::strong_count(&self.0)
    }
}

#[test]
fn test_basic_operations() {
    const L: usize = 3;
    let init = [TestRc::new(), TestRc::new(), TestRc::new()];

    let init_counts = [init[0].count(), init[1].count(), init[2].count()];
    assert_eq!(init_counts, [1, 1, 1]); // 每个初始计数为1

    let mut queue = SlidingQueue::<L, TestRc>::new(init);

    // 验证初始状态
    assert_eq!(queue.len(), L);
    assert_eq!(queue[0].count(), 1);

    // 滑动单个元素
    let new1 = TestRc::new();
    let old1 = queue.slide(new1.clone());
    assert_eq!(old1.count(), 1); // 应被释放
    assert_eq!(queue.len(), L);
    assert_eq!(queue[L - 1].count(), 2); // 新元素计数为2
    drop(new1);

    // 批量滑动
    let new_batch = [TestRc::new(), TestRc::new()];
    let old_batch = queue.slides(new_batch);
    assert_eq!(old_batch[0].count(), 1);
    assert_eq!(old_batch[1].count(), 1);

    // 填满缓冲区触发交换
    let trigger = TestRc::new();
    let _ = queue.slide(trigger); // 此时 start == L，触发交换

    // 验证有效区域
    assert_eq!(queue.len(), L);

    // 获取所有权
    let taken = queue.take();

    taken.iter().for_each(|x| assert_eq!(x.count(), 1)); // 所有权转移后计数仍为1
}

#[test]
fn test_drop_behavior() {
    const L: usize = 2;
    let init = [TestRc::new(), TestRc::new()];

    // 创建队列但不保留所有权
    {
        let mut queue = SlidingQueue::<L, TestRc>::new(init.clone());

        // 滑动一些元素
        let new1 = TestRc::new();
        let _ = queue.slide(new1);

        // 队列在此处被 drop
    }

    // 验证所有元素都被释放
    assert_eq!(init[0].count(), 1);
    assert_eq!(init[1].count(), 1);
}

#[test]
fn test_window_continuity() {
    const L: usize = 4;
    let init = [TestRc::new(), TestRc::new(), TestRc::new(), TestRc::new()];

    let mut queue = SlidingQueue::<L, TestRc>::new(init);

    // 滑动直到触发缓冲区交换
    for _ in 0..L {
        let new = TestRc::new();
        let old = queue.slide(new);
        assert_eq!(old.count(), 1);
    }

    // 验证有效区域包含新元素
    let valid = &*queue;
    assert_eq!(valid.len(), L);

    // 所有元素都应有唯一所有权
    assert!(valid.iter().all(|x| x.count() == 1));
}

#[test]
fn test_clone_and_ownership() {
    const L: usize = 2;
    let init = [TestRc::new(), TestRc::new()];
    let mut queue = SlidingQueue::<L, TestRc>::new(init.clone());

    // 克隆有效区域中的元素
    let cloned = {
        let valid = &*queue;
        valid[0].0.clone() // 增加引用计数
    };

    assert_eq!(init[0].count(), 3); // 原始 + 队列 + 克隆

    // 滑动元素
    let new = TestRc::new();
    let old = queue.slide(new);
    assert_eq!(old.count(), 3); // 被替换元素释放

    // 验证克隆仍有效
    assert_eq!(Rc::strong_count(&cloned), 3);
}
